<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!-- <script src="https://lib.baomitu.com/vue/2.6.14/vue.min.js"></script> -->
  </head>
  <body>
    <div id="app">
      <my-button></my-button>
      <my-button></my-button>
    </div>
    <script src="../dist/vue.js"></script>
    <script>
      /*
        Vue 是 MVVM 框架，（基于 MVC升级，弱化 Controller），有没有完全遵循 mvvm，因为传统 mvvm 框架是不能手动操作数据的，在 vue 中可以手动通过 ref 去操作组件数据

        Vue2 的核心：响应式原理， 使用 defineProperty 来监听数据的变化

          双向绑定主要体现在 v-model 上

          vm.$options 获取到用户传递所有参数

          vue2 中 $开头的属性，是不会变成响应式的，用户如果传递了带有 $的属性会被忽略，处理掉， data:{"$a": 124} vm.$a是获取不到的返回undefined

          vue2 的数据源 props data methods computed watch

          vue2 数组修改数据后实在麻烦就直接覆盖原始数据，暴力


          vue2中的响应式原理就是为对象的每个属性 添加 set 和 get，会递归遍历，因此，用户在写代码的时候对data的数据的对象嵌套不要太过于深，
          vue2中数组的长度和索引没有监控，
          vue2中的数组没有采用 defineProperty ，采用了函数的劫持重写的数组的 7 个方法，用户在调用的时候或执行这个这个方法，用户添加数据时会再次被劫持，后再执行数据的原生方法，因此数组中的对象也是响应式的

          渲染 Watcher： 是默认是创建一个组件，就会生成一个渲染 Watcher，
          v-if 在数据切换后， 需要再重新收集依赖


          依赖收集的流程
          一开始就走 defineReactive 方法把每个属性劫持监听，此时会个每个属性配置对应的 Dep（Dep 的目的是为了收集渲染 Wathcer）
          开始渲染组件之前，把组件的每个 Watcher 先绑定到 Dep.target 上
          开始渲染逻辑就会调用 render 方法，此时发生取值操作，去触发 get 函数，此时 Dep.target 上有对应的渲染 Watcher，就让 dep 和 watcher 创建关系，此时属性中就对应了dep中欧给你的存放的数组 watchers用来存储哪个watcher用到了该属性，同样watcher也会存储这依赖的所有属性 deps
          每个属性有一个 dep，dep记住了对应的watcher


          diff 算法是平级比对
          比对时候，主要比对标签名和 key来判断是不是同一个元素，如果标签和key都一样就认为是同一个元素

          v-for如果有增加或删除，不要使用索引做 key：diff比对是根据key比较

          为什么使用组件？复用，方便维护、组合，性能可以组件级更新

          React 本身是一个 V 框架，只是将数据转换成试图，并没有绑定操作，更新数据也是手动调用 setState 去更新的
          react 的数据源主要在 props 和 state data
      */

      /**
       * computed
       * 本质是 Object.defineProperty,内部封装了 watcher
       * 计算属性具有缓存特性，如果依赖的属性值没有变化，不会执行对应的函数，
       * 计算属性也是一个 Wathcer，内部函数在调用的时候，会做取值操作。
       * 计算属性中依赖的属性变化后，会更新视图，但是计算属性不会收集watcher，对应所依赖的属性会记住是那个watcher
       */

      // 函数式组件，没有类，就是每次调用返回一个虚拟节点，所以函数式组件是没有 watcher 的
      // 全局组件会挂载到原型上，局部组件就是挂载到自己实例身上
      // Vue.component 内部会调用 Vue.extend(); 生成一个组件的子类
      Vue.component("my-button", {
        name: "",
        template: `<button>全局按钮</button>`,
      });

      // const vm = new Vue({
      //   el: "#app",
      //   components: {
      //     "my-button": {
      //       template: `<button>局部按钮</button>`,
      //     },
      //   },
      // });

      const vm = new Vue({
        el: "#app",
        components: {
          "my-button": {
            beforeCreate() {
              console.log("局部按钮 beforeCreate");
            },
            components: {
              "my-com": {
                beforeCreate() {
                  console.log("my-com beforeCreate");
                },
                template: `<span style="color: red;">aaa</span>`,
              },
            },
            template: `<button>局部按钮<my-com></my-com></button>`,
          },
        },
      });
    </script>
  </body>
</html>
